#pragma once
#include <string>
#include <unordered_map>
#include <iostream>
#include <fstream>
#include <regex>

class txt_explain
{
public:
    /**
     * @brief 构造函数，用于创建txt_explain对象
     * @param name 文件名字符串，用于初始化file_name成员变量
     */
    txt_explain(const std::string &name) : file_name(name) {}

    /**
     * @brief 打开文件进行读取操作
     *
     * 该函数首先检查文件是否存在，然后以读取模式打开文件。
     * 如果文件打开失败，将抛出运行时异常。
     *
     * @param 无参数
     * @return 无返回值
     * @throws std::runtime_error 当文件打开失败时抛出异常
     */
    void open(void)
    {
        check_file(file_name);
        file.open(file_name, std::ios::in);
        if (!file.is_open())
            throw std::runtime_error("Failed to open file: " + file_name);
    }
    /**
     * @brief 析构函数，用于关闭文件流
     *
     * 该函数在对象销毁时自动调用，确保文件流被正确关闭。
     * 如果文件流未打开，则直接返回；否则关闭文件流。
     */
    ~txt_explain()
    {
        if (!file.is_open())
            return;
        file.close();
    }
#if 1
    /**
     * 从文件中读取一行数据并解析时间戳和变量信息
     *
     * 该函数读取文件的下一行，解析出时间戳和变量赋值信息。
     * 时间戳格式为 HH:MM:SS:mmm 或 HH:MM:SS-mmm 或 HH:MM:SS.mmm
     * 变量格式为 variable_name = value 的形式
     *
     * @return bool 读取并解析成功返回true，文件结束或读取失败返回false
     */
    bool getline(void)
    {
        std::string line;
        if (!std::getline(file, line))
            return false;

        line_num++;
        std::regex lineRegex(R"(^(\d{2}:\d{2}:\d{2}[\:\-\.]\d{3})\s(.*))");

        std::regex varRegex(R"((\w+\.?\w*)\s*=\s*(-?\d?x?\d+))");

        std::smatch match;
        time_str = "";
        if (std::regex_match(line, match, lineRegex))
        {
            time_str = match[1].str();
            // 输出所有匹配的组
#if 1
            std::string varsStr = match[2].str();
            variables.clear();
            auto varsBegin = std::sregex_iterator(varsStr.begin(), varsStr.end(), varRegex);
            auto varsEnd = std::sregex_iterator();
            for (auto it = varsBegin; it != varsEnd; ++it)
            {
                variables[(*it)[1].str()] = (*it)[2].str();
            }
#endif
        }
        else
        {
            // std::cout << "error: " << line << std::endl;
        }
        // return false;
        return true;
    }
#endif
    /**
     * 打印时间字符串和变量映射表的内容
     *
     * 该函数首先检查时间字符串是否为空，如果不为空则打印时间字符串，
     * 然后遍历变量映射表，打印每个变量名和对应的值，最后换行输出。
     */
    void print_map() const
    {
        if (time_str == "")
            return;
        std::cout << time_str << ": ";

        for (const auto &pair : variables)
        {
            std::cout << pair.first << "=" << pair.second << ", ";
        }
        std::cout << std::endl;
    }
    /**
     * 打印变量映射表的函数
     * @param variable 指定要打印的变量名列表，如果为空则打印所有变量
     * @return 无返回值
     */
    void print_map(const std::vector<std::string> &variable) const
    {
        if (time_str == "")
            return;

        if (variable.empty())
        {
            print_map();
            return;
        }
        bool first = false;
        for (auto &v : variable)
        {
            for (const auto &pair : variables)
            {
                if (pair.first.compare(v) == 0)
                {
                    std::cout << pair.first << "=" << pair.second << ", ";
                    first = true;
                }
            }
        }
        if (first)
            std::cout << std::endl;

#if 0
        std::cout << time_str << ": ";
        for (const auto &pair : variables)
        {
            std::cout << pair.first << "=" << pair.second << ", ";
        }
        std::cout << std::endl;
#endif
    }
    /**
     * @brief 根据键名获取变量值
     * @param key 要查找的变量名
     * @return 如果找到对应的变量则返回其值，否则返回空字符串
     */
    std::string get_var(const std::string &key) const
    {
        auto it = variables.find(key);
        if (it != variables.end())
        {
            return it->second;
        }
        else
        {
            return "";
        }
    }
    /**
     * @brief 获取时间字符串
     *
     * @return const std::string& 返回存储的时间字符串的常量引用
     */
    const std::string &get_time() const
    {
        return time_str;
    }
    /**
     * @brief 获取行号
     *
     * @return int 返回当前对象的行号值
     */
    int get_line_num() const
    {
        return line_num;
    }
    /**
     * @brief 检查指定文件是否存在
     * @param _file 要检查的文件路径
     * @throws std::runtime_error 当文件不存在时抛出异常
     */
    void check_file(const std::string &_file) const
    {
        if (!std::filesystem::exists(_file))
        {
            throw std::runtime_error("The file does not exist: " + _file);
        }
    }

private:
    std::string file_name;
    std::ifstream file;
    int line_num = 0;

    std::string time_str; // 时间
    std::unordered_map<std::string, std::string> variables;
};

#ifndef FILE_OPEN

#define FILE_OPEN(F)                                                \
    try                                                             \
    {                                                               \
        (F)->open();                                                \
        std::cout << "The file opened successfully" << std::endl;   \
    }                                                               \
    catch (const std::exception &e)                                 \
    {                                                               \
        std::cerr << "Caught exception: " << e.what() << std::endl; \
        return 1;                                                   \
    }
#endif